package me.ingxin.android.router

import androidx.collection.ArraySet
import me.ingxin.android.router.annotaions.route.*
import me.ingxin.android.router.utils.Logger
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue

/**
 * Created by ingxin on 2022/4/18
 */
internal class Store {

    /**路由表*/
    private lateinit var routeMap: HashMap<String, RouteMeta>

    /**所有的拦截器*/
    private lateinit var interceptorMeta: ArrayList<InterceptorMeta>

    /**全局类型的拦截器访问频率高，单独缓存*/
    private val globalInterceptorMeta = ArrayList<InterceptorMeta>()

    /**所有组件*/
    private lateinit var components: ArrayList<ComponentMeta>

    fun getComponents(): ArrayList<ComponentMeta> {
        if (!this::components.isInitialized) {
            loadComponent()
        }
        return components
    }

    fun getAllRoute(): Map<String, RouteMeta> {
        if (!this::routeMap.isInitialized) {
            loadRoute()
        }
        return routeMap
    }

    fun getGlobalInterceptor(): Queue<InterceptorMeta> {
        if (!this::interceptorMeta.isInitialized) {
            loadInterceptor()
        }
        //interceptorMeta在注解处理器阶段已经排序了，不用重复排序
        return ConcurrentLinkedQueue(globalInterceptorMeta)
    }

    fun getRelatedInterceptor(meta: RouteMeta): Queue<InterceptorMeta> {
        if (!this::interceptorMeta.isInitialized) {
            loadInterceptor()
        }

        val interceptorSet = ArraySet<InterceptorMeta>()
        meta.interceptorName?.forEach { name ->
            for (item in interceptorMeta) {
                if (item.name == name) {
                    interceptorSet.add(item)
                    break
                }
            }
        }

        meta.interceptor?.forEach { clazz ->
            for (item in interceptorMeta) {
                if (item.destination == clazz) {
                    interceptorSet.add(item)
                    break
                }
            }
        }

        //从路由上读取的拦截器是无序的，需要重新排序
        return PriorityQueue(5, InterceptorComparator()).apply {
            addAll(interceptorSet)
        }
    }

    private fun loadRoute() {
        try {
            val warehouse =
                Class.forName(ROUTE_WAREHOUSE_NAME).newInstance() as IRouteWarehouse
            routeMap = warehouse.getRouteList()
        } catch (ex: ClassNotFoundException) {
            //不存在这个类，说明没有使用@app注解
            Logger.e("can not found @App")
            throw ex
        }
    }

    private fun loadInterceptor() {
        globalInterceptorMeta.clear()
        try {
            val warehouse =
                Class.forName(INTERCEPTOR_WAREHOUSE_NAME).newInstance() as IInterceptorWarehouse
            interceptorMeta = warehouse.getInterceptorList()
            //缓存全局类型拦截器
            for (e in interceptorMeta) {
                if (e.global) {
                    globalInterceptorMeta.add(e)
                }
            }
        } catch (ex: ClassNotFoundException) {
            //不存在这个类，说明没有使用@app注解
            Logger.e("can not found @App")
            throw ex
        }
    }

    private fun loadComponent() {
        try {
            val warehouse =
                Class.forName(COMPONENT_WAREHOUSE_NAME).newInstance() as IComponentWarehouse
            components = warehouse.getComponentList()
        } catch (ex: ClassNotFoundException) {
            //不存在这个类，说明没有使用@app注解
            Logger.e("can not found @App")
            throw ex
        }
    }

    class InterceptorComparator : Comparator<InterceptorMeta> {
        override fun compare(o1: InterceptorMeta, o2: InterceptorMeta): Int =
            o2.priority - o1.priority
    }

    companion object {

        /**拦截器仓库*/
        private const val INTERCEPTOR_WAREHOUSE_NAME =
            "me.ingxin.android.router.annotaions.compiler.InterceptorWarehouse"

        /**路由仓库*/
        private const val ROUTE_WAREHOUSE_NAME =
            "me.ingxin.android.router.annotaions.compiler.RouteWarehouse"

        /**组件仓库*/
        private const val COMPONENT_WAREHOUSE_NAME =
            "me.ingxin.android.router.annotaions.compiler.ComponentWarehouse"

        val instance by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { Store() }
    }

}